//
// ActionManager.cpp
// Usage: Implement of ActionManager class
// Create Date: 2009-02-17
// Author: MaJiuyue
//
#include <SCI.h>
#include <protect.h>
#include <errno.h>
#include "ActionManager.h"
#include "DefaultIRQAction.h"
#include "DefaultExceptionAction.h"
#include "SystemCall.h"
#include "../schedule/Process.h"
#include <time.h>

CActionManager::CActionManager()
{
	for(int i=0; i<IRQ_NR; i++)
		irq_action_list[i] = new IRQAction;

	Resource * res = new Resource(this);
	ResourceManager.CreateResource(res, ServiceCallInterface::ActionManager::ResourceName);
	res->RegisterInterface(
		(Resource::CallInterface3)&CActionManager::exception_handler,
		ServiceCallInterface::ActionManager::SCIID_ExceptionHandler
	);	
	res->RegisterInterface(
		(Resource::CallInterface2)&CActionManager::irq_handler,
		ServiceCallInterface::ActionManager::SCIID_IRQHandler
	);
	res->RegisterInterface(
		(Resource::CallInterface1)&CActionManager::syscall_handler,
		ServiceCallInterface::ActionManager::SCIID_SyscallHandler
	);
	res->RegisterInterface(
		(Resource::CallInterface2)&CActionManager::RegisterIRQAction,
		ServiceCallInterface::ActionManager::SCIID_RegisterIRQAction
	);
	res->RegisterInterface(
		(Resource::CallInterface2)&CActionManager::RemoveIRQAction,
		ServiceCallInterface::ActionManager::SCIID_RemoveIRQAction
	);
	res->RegisterInterface(
		(Resource::CallInterface2)&CActionManager::RegisterExceptionAction,
		ServiceCallInterface::ActionManager::SCIID_RegisterExAction
	);
	res->RegisterInterface(
		(Resource::CallInterface2)&CActionManager::RemoveExceptionAction,
		ServiceCallInterface::ActionManager::SCIID_RemoveExAction
	);
}

bool CActionManager::RegisterIRQAction(u32 irq, IRQAction * action)
{
	irq_action_list[irq]->list_add_tail(action);
	return true;
}

void CActionManager::RemoveIRQAction(IRQAction *action)
{
	action->list_del(action);
}

void CActionManager::RegisterExceptionAction(u32 vec_no, ExceptionAction * action)
{
	exception_action[vec_no] = action;
}

void CActionManager::RemoveExceptionAction(ExceptionAction * action)
{
	for(int i=0; i<EXCEPTION_NR; i++)
		if(exception_action[i] == action)
			exception_action[i] = NULL;
}

void CActionManager::irq_handler(u32 irq, regs_t *regs)
{
	list_head<IRQAction> * lst = this->irq_action_list[irq];
	IRQAction::iterator it = lst->begin();
	while(it!=lst->end())
	{
		(*it)(irq, regs);
		++it;
	}
}

void CActionManager::exception_handler(u32 vec_no, u32 err_code, regs_t *regs)
{
	ExceptionAction * action = this->exception_action[vec_no];
	if(action!=NULL)
		(*action)(vec_no, err_code, regs->eip, regs->cs, regs->eflags);
	else
		default_exception_action(vec_no, err_code, regs->eip, regs->cs, regs->eflags);
}

#include <bootutil.h>
extern "C" void CallUser(u32 eip, u32 esp);
void CActionManager::syscall_handler(regs_t *regs)
{
	u32 ret = 0;
	switch(regs->eax)
	{
		case SYSCALL_SBRK:
			ret = SystemCall::do_sbrk(regs->ebx);
			break;

		case SYSCALL_GETPID:
			ret = SystemCall::do_getpid();
			break;

		case SYSCALL_FORK:
			ret = SystemCall::do_fork();
			break;
		case SYSCALL_EXIT:
			ret = SystemCall::do_exit();
			break;
		case SYSCALL_BLOCK:
			SystemCall::do_block(regs->ebx);
			break;
		case SYSCALL_WAITPID:	
			ret = SystemCall::do_waitpid(regs->ebx);
			break;
		case SYSCALL_WAKEUP:
			SystemCall::do_wakeup(regs->ebx);
			break;

		case SYSCALL_SEND:
			ret = SystemCall::do_send(regs->ebx, regs->ecx);
			break;

		case SYSCALL_RECEIVE:
			ret = SystemCall::do_receive(regs->ebx, regs->ecx);
			break;
		
		case SYSCALL_OPEN:
			ret = SystemCall::do_open(regs);
			break;

		case SYSCALL_READ:
			ret = SystemCall::do_read(regs);
			break;

		case SYSCALL_WRITE:
			ret = SystemCall::do_write(regs);
			break;

		case SYSCALL_MKDEV:
			ret = SystemCall::do_mkdev(regs);
			break;

		case SYSCALL_GETTIMEOFDAY:
			ret = SystemCall::do_gettimeofday(regs);
			break;
	
		case SYSCALL_NL_MAPADDRESS:
			ret = SystemCall::do_MapAddress(regs);
			break;
		
		case SYSCALL_NL_UNMAPADDRESS:
			ret = SystemCall::do_UnmapAddress(regs);
			break;
		
		case SYSCALL_NL_REGISTERIRQ:
			ret = SystemCall::do_RegisterIRQ(regs);
			break;

		case SYSCALL_NL_UNREGISTERIRQ:
			ret = SystemCall::do_UnRegisterIRQ(regs);
			break;
		
		case SYSCALL_NL_FINISHREQUEST:
			ret = SystemCall::do_FinishRequest(regs);
			break;
		
		case SYSCALL_NL_SETPRIORITY:
			ret = SystemCall::do_SetPriority(regs);
			break;

		default:
			kprintf("%c", regs->eax);
			break;
	}

	if(ret!=EJUSTRETURN)
		GetCurrentProcess()->GetThread()->SetRegisterValue(REGS_EAX, ret); 
}

